// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

package com.jfsoft.cef;

import com.jfsoft.cef.dialog.DownloadDialog;
import com.jfsoft.cef.handler.*;
import com.jfsoft.cef.server.WsServer;
import com.jfsoft.cef.ui.ControlPanel;
import com.jfsoft.cef.ui.StatusPanel;
import org.cef.CefApp;
import org.cef.CefApp.CefVersion;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.OS;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefMessageRouter;
import org.cef.handler.CefDisplayHandlerAdapter;
import org.cef.handler.CefLoadHandlerAdapter;
import org.java_websocket.WebSocketImpl;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Properties;

public class MainFrame extends BrowserFrame {
    private static final long serialVersionUID = -2295538706810864538L;
    private String cache_path = "./cache";

    public static void main(String[] args) {
        // OSR mode is enabled by default on Linux.
        // and disabled by default on Windows and Mac OS X.
        boolean osrEnabledArg = OS.isLinux();
        String cookiePath = null;
//        for (String arg : args) {
//            arg = arg.toLowerCase();
//            if (!OS.isLinux() && arg.equals("--off-screen-rendering-enabled")) {
//                osrEnabledArg = true;
//            } else if (arg.startsWith("--cookie-path=")) {
//                cookiePath = arg.substring("--cookie-path=".length());
//                File testPath = new File(cookiePath);
//                if (!testPath.isDirectory() || !testPath.canWrite()) {
//                    System.out.println("Can't use " + cookiePath + " as cookie directory. Check if it exists and if it is writable");
//                    cookiePath = null;
//                } else {
//                    System.out.println("Storing cookies in " + cookiePath);
//                }
//            }
//        }

        System.out.println("Offscreen rendering " + (osrEnabledArg ? "enabled" : "disabled"));

        // MainFrame keeps all the knowledge to display the embedded browser
        // frame.
        final MainFrame frame = new MainFrame(osrEnabledArg, cookiePath, args);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                CefApp.getInstance().dispose();
                frame.dispose();
            }
        });

//        Image icon = Toolkit.getDefaultToolkit().getImage("./image/logo.gif");
//        frame.setSize(1200, 800);
//        frame.setIconImage(new Image);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setVisible(true);

        // websocket
        WebSocketImpl.DEBUG = false;
        int port = 8888; // 端口
        WsServer s = new WsServer(port);
        s.start();
    }

    private final CefClient client_;
    private String errorMsg_ = "";
    private final CefBrowser browser_;
    private ControlPanel control_pane_;
    private StatusPanel status_panel_;
//    private final CefCookieManager cookieManager_;

    public MainFrame(boolean osrEnabled, String cookiePath, String[] args) {

        // 1) CefApp is the entry point for JCEF. You can pass
        //    application arguments to it, if you want to handle any
        //    chromium or CEF related switches/attributes in
        //    the native world.
        CefSettings settings = new CefSettings();
        settings.windowless_rendering_enabled = false;
        settings.cache_path = cache_path;
        settings.remote_debugging_port = 8088;
        settings.persist_session_cookies = true;
        // try to load URL "about:blank" to see the background color
//        settings.background_color = settings.new ColorType(100, 255, 242, 211);
        CefApp myApp = CefApp.getInstance(settings);
        CefVersion version = myApp.getVersion();
        System.out.println("Using:\n" + version);

        //    We're registering our own AppHandler because we want to
        //    add an own schemes (search:// and client://) and its corresponding
        //    protocol handlers. So if you enter "search:something on the web", your
        //    search request "something on the web" is forwarded to www.google.com
        CefApp.addAppHandler(new AppHandler(args));

        //    By calling the method createClient() the native part
        //    of JCEF/CEF will be initialized and an  instance of
        //    CefClient will be created. You can create one to many
        //    instances of CefClient.
        client_ = myApp.createClient();

        // 2) You have the ability to pass different handlers to your
        //    instance of CefClient. Each handler is responsible to
        //    deal with different informations (e.g. keyboard input).
        //
        //    For each handler (with more than one method) adapter
        //    classes exists. So you don't need to override methods
        //    you're not interested in.
        DownloadDialog downloadDialog = new DownloadDialog(this);
        client_.addContextMenuHandler(new ContextMenuHandler(this));
        client_.addDownloadHandler(downloadDialog);
        client_.addDragHandler(new DragHandler());
        client_.addGeolocationHandler(new GeolocationHandler(this));
        client_.addJSDialogHandler(new JSDialogHandler());
        client_.addKeyboardHandler(new KeyboardHandler(this));
        client_.addRequestHandler(new RequestHandler(this));

        //    Beside the normal handler instances, we're registering a MessageRouter
        //    as well. That gives us the opportunity to reply to JavaScript method
        //    calls (JavaScript binding). We're using the default configuration, so
        //    that the JavaScript binding methods "cefQuery" and "cefQueryCancel"
        //    are used.
        CefMessageRouter msgRouter = CefMessageRouter.create();
        msgRouter.addHandler(new MessageRouterHandler(), true);
        msgRouter.addHandler(new MessageRouterHandlerEx(client_), false);
        client_.addMessageRouter(msgRouter);

        // 2.1) We're overriding CefDisplayHandler as nested anonymous class
        //      to update our address-field, the title of the panel as well
        //      as for updating the status-bar on the bottom of the browser
        client_.addDisplayHandler(new CefDisplayHandlerAdapter() {
            @Override
            public void onAddressChange(CefBrowser browser, String url) {
                control_pane_.setAddress(browser, url);
            }

            @Override
            public void onTitleChange(CefBrowser browser, String title) {
                setTitle(title);
            }

            @Override
            public void onStatusMessage(CefBrowser browser, String value) {
                status_panel_.setStatusText(value);
            }
        });

        // 2.2) To disable/enable navigation buttons and to display a prgress bar
        //      which indicates the load state of our website, we're overloading
        //      the CefLoadHandler as nested anonymous class. Beside this, the
        //      load handler is responsible to deal with (load) errors as well.
        //      For example if you navigate to a URL which does not exist, the
        //      browser will show up an error message.
        client_.addLoadHandler(new CefLoadHandlerAdapter() {


            @Override
            public void onLoadingStateChange(CefBrowser browser,
                                             boolean isLoading,
                                             boolean canGoBack,
                                             boolean canGoForward) {
                control_pane_.update(browser, isLoading, canGoBack, canGoForward);
                status_panel_.setIsInProgress(isLoading);

                if (!isLoading && !errorMsg_.isEmpty()) {
                    browser.loadString(errorMsg_, control_pane_.getAddress());
                    errorMsg_ = "";
                }
            }

            @Override
            public void onLoadError(CefBrowser browser,
                                    int frameIdentifer,
                                    ErrorCode errorCode,
                                    String errorText,
                                    String failedUrl) {
                if (errorCode != ErrorCode.ERR_NONE && errorCode != ErrorCode.ERR_ABORTED) {
                    errorMsg_ = "<html><head>";
                    errorMsg_ += "<title>Error while loading</title>";
                    errorMsg_ += "</head><body>";
                    errorMsg_ += "<h1>" + errorCode + "</h1>";
                    errorMsg_ += "<h3>Failed to load " + failedUrl + "</h3>";
                    errorMsg_ += "<p>" + (errorText == null ? "" : errorText) + "</p>";
                    errorMsg_ += "</body></html>";
                    browser.stopLoad();
                }
            }
        });

        // 3) Before we can display any content, we require an instance of
        //    CefBrowser itself by calling createBrowser() on the CefClient.
        //    You can create one to many browser instances per CefClient.
        //
        //    If the user has specified the application parameter "--cookie-path="
        //    we provide our own cookie manager which persists cookies in a directory.
//        CefRequestContext requestContext = null;
//        if (cookiePath != null) {
//            cookieManager_ = CefCookieManager.createManager(cookiePath, false);
//            requestContext = CefRequestContext.createContext(
//                    new CefRequestContextHandlerAdapter() {
//                        @Override
//                        public CefCookieManager getCookieManager() {
//                            return cookieManager_;
//                        }
//                    });
//        } else {
//            cookieManager_ = CefCookieManager.getGlobalManager();
//        }

        Properties properties = new Properties();
        String url = null;
        // 使用ClassLoader加载properties配置文件生成对应的输入流
        try {
            BufferedReader bufferedReader = new BufferedReader(new FileReader("./config/config.properties"));
            if (bufferedReader != null) {
                properties.load(bufferedReader);
                url = properties.getProperty("app.default.url");
            } else {
                url = "http://www.baidu.com";
            }
        } catch (Exception e) {
            url = "http://www.baidu.com";
            e.printStackTrace();
        }
        browser_ = client_.createBrowser(url, false, false);

        setBrowser(client_, browser_);

        //    Last but not least we're setting up the UI for this example implementation.
        getContentPane().add(createContentPanel(), BorderLayout.CENTER);
//        MenuBar menuBar = new MenuBar(this,
//                browser_,
//                control_pane_,
//                downloadDialog,
//                cookieManager_);
//
//        menuBar.addBookmark("Binding Test", "file:///www/binding_test.html");
//        menuBar.addBookmark("Binding Test 2", "file:///www/binding_test2.html");
//        menuBar.addBookmark("Download Test", "http://cefbuilds.com");
//        menuBar.addBookmark("Geolocation Test", "http://slides.html5rocks.com/#geolocation");
//        menuBar.addBookmark("Login Test (username:pumpkin, password:pie)", "http://www.colostate.edu/~ric/protect/your.html");
//        menuBar.addBookmark("Certificate-error Test", "https://www.k2go.de");
//        menuBar.addBookmark("Resource-Handler Test", "http://www.foo.bar/");
//        menuBar.addBookmark("Scheme-Handler Test 1: (scheme \"client\")", "client://tests/handler.html");
//        menuBar.addBookmark("Scheme-Handler Test 2: (scheme \"search\")", "search://do a barrel roll/");
//        menuBar.addBookmark("Spellcheck test", "file:///www/spellcheck.html");
//        menuBar.addBookmark("Test local Storage", "file:///www/localstorage.html");
//        menuBar.addBookmarkSeparator();
//        menuBar.addBookmark("javachromiumembedded", "https://bitbucket.org/chromiumembedded/java-cef");
//        menuBar.addBookmark("chromiumembedded", "https://bitbucket.org/chromiumembedded/cef");
//        setJMenuBar(menuBar);
    }

    private JPanel createContentPanel() {
        JPanel contentPanel = new JPanel(new BorderLayout());
        control_pane_ = new ControlPanel(browser_);
        status_panel_ = new StatusPanel();
//        contentPanel.add(control_pane_, BorderLayout.NORTH);

        // 4) By calling getUIComponen() on the CefBrowser instance, we receive
        //    an displayable UI component which we can add to our application.
        contentPanel.add(browser_.getUIComponent(), BorderLayout.CENTER);

//        contentPanel.add(status_panel_, BorderLayout.SOUTH);
        return contentPanel;
    }
}
